﻿/******************************************************************
  遍历DLL导出信息
  32位程序才能正常运行
  @Arcadia 2021-04-22
******************************************************************/

#include <io.h>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <iostream>

/**
 * C++获取指定目录下的所有文件
 * 列出文件夹下所有文件
 */
void getAllFiles(std::string path, std::vector<std::string>& files)
{
	// 文件句柄
	long hFile = 0;
	// 文件信息
	struct _finddata_t fileinfo;

	std::string p;

	if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) {
		do {
			// 保存文件的全路径
			//std::cout << "" << path <<"\t\t"<< fileinfo.name << std::endl;
			files.push_back(p.assign(path).append("\\").append(fileinfo.name));

		} while (_findnext(hFile, &fileinfo) == 0); //寻找下一个，成功返回0，否则-1

		_findclose(hFile);
	}
}

#include <comutil.h>
//#include <afxcontrolbars.h> 有加windows.h就不用加这句
#pragma comment(lib, "comsuppw.lib")
//inline std::string W2A(const wchar_t* source)
//{
//	_bstr_t  a(source);
//	return  std::string(a);
//}
std::string W2A(const wchar_t* source)
{
	char output[256];
	sprintf_s(output, "%ws", source);
	return std::string(output);
}


std::string Utf8ToGbk(const char *src_str)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, src_str, -1, NULL, 0);
	wchar_t* wszGBK = new wchar_t[len + 1];
	memset(wszGBK, 0, len * 2 + 2);
	MultiByteToWideChar(CP_UTF8, 0, src_str, -1, wszGBK, len);
	len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
	char* szGBK = new char[len + 1];
	memset(szGBK, 0, len + 1);
	WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
	std::string strTemp(szGBK);
	if (wszGBK) delete[] wszGBK;
	if (szGBK) delete[] szGBK;
	return strTemp;
}

#include <iostream>
#include <regex>
/**
 * 从字符串信息中分解出所需的信息
 * @param std::string Sample 从控制台拷来的字符串
 * @return std::vector<std::string> 结果集
 */
std::vector<std::string> getFunctionNameByRegex(std::string Sample)
{
	// 3段:
	std::regex _reg("([0-9]*)[ ]{1,3}([A-Z0-9]*)[ ]+([A-Z0-9]*)[ ? ]+([A-Za-z0-9_]+)([@$?]+)([A-Za-z0-9_]+)([@$?]+)([A-Za-z0-9_]+)([@$?]+)([A-Za-z0-9_]+)");//\\d //{1,11}//([A-Za-z1-9_]{1,11})    ([@]+)([A-Za-z0-9_]*])    
	std::regex _reg2("([0-9]*)[ ]{1,3}([A-Z0-9]*)[ ]+([A-Z0-9]*)[ ? ]+([A-Za-z0-9_]+)([@$?]+)([A-Za-z0-9_]+)([@$?]+)([A-Za-z0-9_]+)");//\\d //{1,11}//([A-Za-z1-9_]{1,11})    ([@]+)([A-Za-z0-9_]*])    
	std::regex _reg1("([0-9]*)[ ]{1,3}([A-Z0-9]*)[ ]+([A-Z0-9]*)[ ? ]+([A-Za-z0-9_]+)");//\\d //{1,11}//([A-Za-z1-9_]{1,11})    ([@]+)([A-Za-z0-9_]*])    
	std::smatch result;
	bool ret = std::regex_search(Sample, result, _reg);
	if (!ret)
	{
		ret = std::regex_search(Sample, result, _reg2);
	}
	if (!ret)
	{
		std::regex_search(Sample, result, _reg1);
	}
	// 结果集:
	std::vector<std::string> resultPack;
	for (size_t i = 4; i < result.size(); i += 2)
	{
		resultPack.push_back(result.str(i));
	}
	return resultPack;
}

int main()
{
	std::vector<std::string> files;
	getAllFiles("E:\\SVN_Debug_2021-04-20\\adpluscpp\\sdk\\bin\\debug", files);


	// 取目录下所有的txt文件:
	std::cout << "取目录下所有的txt文件" << std::endl;
	std::vector<std::string> txtFiles01;
	for (auto iterA = files.begin(); iterA != files.end(); ++iterA)
	{
		if (-1 != iterA->find(".txt"))
		{
			txtFiles01.push_back(*iterA);
		}
	}

	// 记录字符串对应的文件:
	// 用vector的原因是, 担心有两个文件的某行一模一样
	std::vector<std::pair<std::string, std::string>> databaseLineByFile;
	std::map<std::string, std::string> databaseMapLineByFile;

	// 读取每个文件:
	// 文件内容夹着空格, 去掉空格:
	std::cout << "文件内容夹着空格, 去掉空格" << std::endl;
	std::vector<std::string> txtFiles02;
	for (auto iterA = txtFiles01.begin(); iterA != txtFiles01.end(); ++iterA)
	{
		const std::string &filename = *iterA;
		std::ifstream file;
		file.open(filename);
		if (!file.is_open())
		{
			std::cout << "有错误！文件未被打开\n";
			continue;
		}
		std::string line;
		while (getline(file, line))
		{
			size_t charIndex = 0;
			std::string strLine;
			bool hasAt = false;
			for (auto iterA = line.begin(); iterA != line.end(); ++iterA)
			{
				if (++charIndex % 2)
				{
					continue;
				}
				//std::cout << *iterA;
				if ('@' == *iterA)
				{
					hasAt = true;
				}
				strLine.push_back(*iterA);
			}
			//std::cout << std::endl;
			strLine.push_back('\0');

			if (hasAt)
			{
				txtFiles02.push_back(strLine);
				databaseLineByFile.push_back({ strLine,filename });
				databaseMapLineByFile[strLine] = filename;
			}
		}// END while
	}

	// 同名函数出现的次数 记录每个函数名在哪些地方出现过
	std::map<std::string, std::vector<std::string>> functionNameBySpace1;
	// 若有上层命名空间相同, 那么更上一层是否依然相同
	std::map<std::string, std::vector<std::string>> functionNameBySpace2;

	// 分离出关键的函数名 及类名命名空间等信息
	std::cout << "分离出关键的函数名 及类名命名空间等信息" << std::endl;
	for (auto iterA = txtFiles02.begin(); iterA != txtFiles02.end(); ++iterA)
	{
		//std::cout << *iterA << std::endl;
		std::vector<std::string> strList = getFunctionNameByRegex(*iterA);

		bool first = true;
		std::string firstStr;
		std::string strSpace1;// 命名空间1
		bool second = true;
		std::string secondStr;
		std::string strSpace2;// 命名空间2
		for (size_t i = 0; i < strList.size(); ++i)
		{
			if (!first)
			{
				strSpace1 +=" @ " + strList.at(i);
			}
			if (!second)
			{
				strSpace2 += " @ " + strList.at(i);
			}

			if (0 == i)
			{
				firstStr = strList.at(i);
				first = false;
			}
			if(1 == i)
			{
				secondStr = firstStr+"\t"+strList.at(i);
				second = false;
			}
		}

		// 插入来自文件:
		const std::string &_ByFile = databaseMapLineByFile[*iterA];


		functionNameBySpace1[firstStr].push_back(strSpace1+" \tByFile:"+ _ByFile);
		functionNameBySpace2[secondStr].push_back(strSpace2+ " \tByFile:" + _ByFile);
	}

	std::cout << "\n\n1层函数名:" << std::endl;
	std::ofstream fs1("conflictLevel1.txt",std::ios::out);
	for (auto iterKey = functionNameBySpace1.begin(); iterKey != functionNameBySpace1.end(); ++iterKey)
	{
		const std::string &keyString = iterKey->first;
		if(iterKey->second.size()>1)
		{
			std::cout << "\t"<< keyString << std::endl;
			fs1 << "\t" << keyString << std::endl;
			for (auto iterList = iterKey->second.begin(); iterList != iterKey->second.end(); ++iterList)
			{
				std::cout << "\t\t" << *iterList << std::endl;
				fs1 << "\t\t" << *iterList << std::endl;
			}
		}
	}

	std::cout << "\n\n2层函数名:" << std::endl;
	std::ofstream fs2("conflictLevel2.txt", std::ios::out);

	for (auto iterKey = functionNameBySpace2.begin(); iterKey != functionNameBySpace2.end(); ++iterKey)
	{
		const std::string &keyString = iterKey->first;
		if (iterKey->second.size() > 1)
		{
			std::cout << "\t" << keyString << std::endl;
			fs2 << "\t" << keyString << std::endl;
			for (auto iterList = iterKey->second.begin(); iterList != iterKey->second.end(); ++iterList)
			{
				std::cout << "\t\t" << *iterList << std::endl;
				fs2 << "\t\t" << *iterList << std::endl;
			}
		}
	}



	return 0;
}
